package com.toutiao.issue

import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.{HashMap => HMap}

class WAND(I:InvertIndex[String], query:Map[String,Double], t:Double) {

  val invertIndex = I
  val qs = query.map(_._1).filter( v => invertIndex.contains(v) && invertIndex(v).length > 0)
  val T = t
  
  var currentDocumentID = -1L
  
  var currentInvertIndex = qs.map(v => {
    (v,(invertIndex(v)(0),0))
  }).toMap
  
  val UB = query

  var sortQs = qs.map(v => {
    (currentInvertIndex(v)._1,v)
  }).toArray
  
  def _sortQs() { // 这里耗时较大
    sortQs = sortQs.sortWith( (x1,x2) => x1._1 < x2._1 )
  }
  
  def _searchPivot():(String,Int) = {
    var score = 0.0
    var i = -1
    
    while (score < T && i+1 < sortQs.length && sortQs.length > 0){
      val v = sortQs(i+1)._2
      score += UB(v)
      i += 1
    }
    
    if (score >= T){
      (sortQs(i)._2,i)
    } else {
      ("",sortQs.length)
    }
  }
  
  def _iteratorInvertInde(term:String, pos:Int, docID:Long) = {
    val list = invertIndex(term)
    var i = pos
    var z = 0
    while (z < 1 && i < list.length){
      if (list(i) >= docID){
        z = 1
      } else {
        i += 1
      }
    }
    if (z == 1)
      (list(i),i)
    else
      (Long.MaxValue,i)
  }
  
  def _incrementTerm(index:Int, docID:Long) {
    val term = sortQs(index)._2
    val pos = currentInvertIndex(term)._2
    val (newDocID,newPos) = _iteratorInvertInde(term,pos,docID)
    currentInvertIndex += term -> (newDocID,newPos)
    sortQs(index) = (newDocID,term)
  }
  
  def _next:Long = {
    if (currentDocumentID == Long.MaxValue) {
      -1L
    }
    else {
      var isCandidate = 0
      var candidate = -1L
      while (isCandidate < 1){
        _sortQs
        val (pivotTerm,pivotIndex) = _searchPivot
        
        if (pivotTerm == ""){
          isCandidate = 1 // 1
        } else {   
          val pivotDocID = currentInvertIndex(pivotTerm)._1
          if (pivotDocID == Long.MaxValue){
            isCandidate = 2 // 2
          } 
          else if (pivotDocID <= currentDocumentID){
            val index = 0
            _incrementTerm(index,currentDocumentID+1)
          }
          else {
            val docID = sortQs(0)._1
            if (pivotDocID == docID){
              currentDocumentID = pivotDocID
              candidate = currentDocumentID
              isCandidate = 3
            }
            else {
              for (i <- 0 until pivotIndex){
                _incrementTerm(i,pivotDocID)
              }
            }
          }
        }
      }
      candidate
    }
  }
  
  
  def retrieve = {  
    val ns = new ArrayBuffer[Long]  
    var c = _next
    while (c != -1){
      ns += c
      c = _next
    }
    ns.toArray
  }  
  
}
